﻿using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using Ongoal.Quotation.Common;
using Ongoal.Quotation.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ongoal.Quotation.APIBase
{
    /// <summary>
    /// 树形表操作
    /// </summary>
    [Route("Tree")]
    public class TreeTableController : WebAPIBase
    {
        private List<string> _baseModeProList = new List<string>();
        private List<string> _baseModeUpdateProList = new List<string>();
        private List<string> _treeModeProList = new List<string>();

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public TreeTableController()
        {
            _baseModeProList = typeof(ModelBase).GetProperties().Select(t => t.Name).ToList();
            _baseModeUpdateProList = typeof(ModelBase).GetProperties().Where(t => t.Name != "ID").Select(t => t.Name).ToList();
            _treeModeProList = typeof(TreeBase<dynamic>).GetProperties().Where(t=>!_baseModeProList.Contains(t.Name) && t.Name != "Children").Select(t => t.Name).ToList();
        }

        /// <summary>
        /// 获取单条数据（包含子节点 ）不需要子节点请请求Auto
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="id">记录ID</param>
        /// <returns>单条数据</returns>
        /// <exception cref="ArgumentException"></exception>
        [HttpGet("{tableName}/{id?}")]
        public dynamic GetFlow(string tableName, [FromRoute] int id = 0)
        {
            if (string.IsNullOrEmpty(tableName) || id <= 0)
            {
                throw new ArgumentException("表名及记录ID不可为空");
            }
            var root = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where("Deleted=0 AND ID=@ID", new { ID = id }).First();
            if (root == null)
            {
                throw new KeyNotFoundException("无法找到对应的记录");
            }
            var childrenList = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where("Deleted=0 AND PropPath like @IDPath", new { IDPath = $"%/{id}/%" }).ToList();
            BuildTree(root, childrenList);
            return root;
        }

        /// <summary>
        /// 获取树形表的根数据集合(按树形组合)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns>数据集合</returns>
        /// <exception cref="ArgumentException"></exception>
        [HttpGet("{tableName}")]
        public List<dynamic> GetAll(string tableName)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new ArgumentException("表名不可为空");
            }
            var allData = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).ToList();
            if (allData != null && allData.Count > 0)
            {
                var rootList = allData.Where(t => t.ParentID == 0).ToList();
                foreach (var item in rootList)
                {
                    BuildTree(item, allData);
                }
                return rootList;
            }
            else
            { 
                return new List<dynamic>();
            }
        }

        /// <summary>
        /// 分页获取表的数据集合
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="size">分页大小(不可为空，如果小于0则默认为30)</param>
        /// <param name="index">页码(不可为空，如果小于0则默认为1)</param>
        /// <returns>数据集合</returns>
        /// <exception cref="ArgumentException"></exception>
        [HttpGet("{tableName}/{size?}/{index?}")]
        public SectionModel GetAll(string tableName, [FromRoute] int size, [FromRoute] int index)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new ArgumentException("表名不可为空");
            }
            SectionModel section = new SectionModel();
            if (size > 0)
            {
                section.Size = size;
            }
            if (index > 0)
            {
                section.Index = index;
            }
            int totalCount = 0;
            section.Items = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where("Deleted=0 AND ParentID = 0").ToPageList(section.Index, section.Size, ref totalCount);
            section.Count = totalCount;
            if (section.Items.Count > 0)
            {
                foreach (var item in section.Items)
                {
                    var childrenList = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where("Deleted=0 AND PropPath like @IDPath", new { IDPath = $"{item.PropPath}{item.ID}/%" }).ToList();
                    BuildTree(item, childrenList);
                }
            }
            return section;
        }

        /// <summary>
        /// 搜索数据（适应vxe-table树形表）
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="model">搜索实体</param>
        /// <returns></returns>
        [HttpPost("Search/{tableName}/")]
        public SectionModel Search(string tableName, [FromBody] SearchModel model)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new ArgumentException("表名不可为空");
            }
            if (model == null)
            {
                throw new ArgumentException("搜索参数不可为空");
            }
            SectionModel section = new SectionModel();
            string keySearch = string.Empty;
            var keyParametars = new Dictionary<string, object>();
            if (!string.IsNullOrEmpty(model.KeyWord))
            {
                keyParametars.Add("@searchKey", $"%{model.KeyWord}%");
                if (model.KeyColList != null && model.KeyColList.Count > 0)
                {
                    StringBuilder builder = new StringBuilder();
                    foreach (var keyCol in model.KeyColList)
                    {
                        builder.Append($"OR {keyCol} like @searchKey ");
                    }
                    if (builder.Length > 0)
                    {
                        keySearch = builder.ToString().Substring(2);
                    }
                }
                else
                {
                    throw new ArgumentException("请指定关键字搜索列");
                }
            }
            StringBuilder condition = new StringBuilder();
            Dictionary<string, object> ConditionObj = new Dictionary<string, object>();
            if (model.Condition != null)
            {
                foreach (JProperty propertyInfo in model.Condition)
                {
                    condition.Append($"And {propertyInfo.Name}=@{propertyInfo.Name} ");
                    ConditionObj.Add(propertyInfo.Name, propertyInfo.Value);
                }
            }
            var conditionStr = condition.Length > 0 ? condition.ToString().Substring(3) : "";

            var allnodes = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName)
                .Where(" Deleted=0 ")
                .WhereIF(!string.IsNullOrEmpty(keySearch), keySearch, keyParametars)
                .WhereIF(condition.Length > 0, conditionStr, ConditionObj).ToList();

            section.Items = allnodes;
            section.Count = allnodes.Count;
            return section;
        }

        /// <summary>
        /// 新增单条数据
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="obj">新增信息实体</param>
        /// <returns>新增对象的键值对</returns>
        /// <exception cref="ArgumentException"></exception>
        [HttpPost("{tableName}")]
        public dynamic Post(string tableName, [FromBody] InfoModel obj)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new ArgumentException("表名不可为空");
            }
            if (obj == null)
            {
                throw new ArgumentException("参数不可为空");
            }
            var insertObj = new Dictionary<string, object>();

            foreach (JProperty propertyInfo in obj.Data)
            {
                if (_baseModeProList.Contains(propertyInfo.Name) || propertyInfo.Name.StartsWith("_X_"))
                {
                    //忽略基础属性
                    continue;
                }
                if (insertObj.ContainsKey(propertyInfo.Name))
                {
                    insertObj[propertyInfo.Name] = propertyInfo.Value;
                }
                else
                {
                    insertObj.Add(propertyInfo.Name, propertyInfo.Value);
                }
            }
            try
            {
                if (obj.Check)
                {
                    //需要检查数据是否合法
                }
                if (obj.RepeatKeys != null && obj.RepeatKeys.Count > 0)
                {
                    //需要检查数据是否重复
                    StringBuilder stringBuilder = new StringBuilder();
                    var parametars = new Dictionary<string, object>();
                    foreach (var keyStr in obj.RepeatKeys)
                    {
                        if (insertObj.ContainsKey(keyStr))
                        {
                            stringBuilder.Append($"And {keyStr}=@{keyStr} ");
                            parametars.Add(keyStr, insertObj[keyStr]);
                        }
                    }
                    if (stringBuilder.Length > 0)
                    {
                        var whereStr = stringBuilder.ToString().Substring(3);

                        if (this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where(whereStr, parametars).Count() > 0)
                        {
                            throw new Exception("存在重复数据");
                        }
                    }
                }
                ////////////////////////////////////////////////////////////
                //////添加基础属性
                ///////////////////////////////////////////////////////////
                insertObj.Add("CreatorID", this.CurrentUser.UserID);
                insertObj.Add("ModifyID", this.CurrentUser.UserID);
                insertObj.Add("CreateTime", DateTime.Now);
                insertObj.Add("ModifyTime", DateTime.Now);
                insertObj.Add("Deleted", 0);
                //////////////////////////////////////////////////////////


                ////////////////////////////////////////////////////////////
                //////树结构表基础属性处理
                ///////////////////////////////////////////////////////////
                if (insertObj.ContainsKey("ParentID") && Convert.ToInt32(insertObj["ParentID"]) > 0)
                {
                    //指定了父节点，需要将父节点找出来，然后赋值
                    var parentNode = this.Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where("Deleted=0 AND ID=@ID", new { ID = insertObj["ParentID"] }).First();
                    if (parentNode != null)
                    {
                        insertObj.Remove("PropPath");
                        insertObj.Remove("NodeLevel");
                        insertObj.Add("PropPath", $"{parentNode.PropPath}{parentNode.ID}/");
                        insertObj.Add("NodeLevel", parentNode.NodeLevel + 1);
                    }
                    else
                    {
                        throw new ArgumentException("指定的父节点不存在");
                    }
                }
                else 
                {
                    //赋值为根节点
                    foreach (var key in _treeModeProList)
                    {
                        insertObj.Remove(key);
                    }

                    insertObj.Add("ParentID", 0);
                    insertObj.Add("PropPath", "/");
                    insertObj.Add("NodeLevel", 1);
                    insertObj.Add("Deleted", 0);
                }

                //////////////////////////////////////////////////////////

                var result = this.Db!.GetDbContext(string.Empty).Insertable(insertObj).AS(tableName).ExecuteReturnBigIdentity();
                if (result > 0)
                {
                    obj.Data.ID = result;
                    return obj.Data;
                }
                throw new Exception("保存数据失败!");
            }
            catch
            {
                throw;
            }
        }


        /// <summary>
        /// 修改单条数据
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="obj">修改信息实体</param>
        /// <returns>修改后的键值对</returns>
        /// <exception cref="ArgumentException"></exception>
        [HttpPut("{tableName}")]
        public dynamic PUT(string tableName, [FromBody] InfoModel obj)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new ArgumentException("表名不可为空");
            }
            if (obj == null)
            {
                throw new ArgumentException("参数不可为空");
            }
            var updateObj = new Dictionary<string, object>();
            foreach (JProperty propertyInfo in obj.Data)
            {
                if (_baseModeUpdateProList.Contains(propertyInfo.Name) || propertyInfo.Name.StartsWith("_X_"))
                {
                    //忽略基础属性
                    continue;
                }
                if (updateObj.ContainsKey(propertyInfo.Name))
                {
                    updateObj[propertyInfo.Name] = propertyInfo.Value;
                }
                else
                {
                    updateObj.Add(propertyInfo.Name, propertyInfo.Value);
                }
            }
            if (!updateObj.ContainsKey("ID"))
            {
                throw new ArgumentException("参数中不存在主键");
            }
            ////////////////////////////////////////////////////////////
            //////添加基础属性
            ///////////////////////////////////////////////////////////
            updateObj.Add("ModifyID", this.CurrentUser.UserID);
            updateObj.Add("ModifyTime", DateTime.Now);
            //////////////////////////////////////////////////////////
            

            var objNode = this.Db!.GetDbContext(string.Empty).Queryable<TreeBase<dynamic>>().AS(tableName).Where("ID=@ID", new { ID = updateObj["ID"] }).First();
            ////////////////////////////////////////////////////////////
            //////树结构表基础属性处理
            ///////////////////////////////////////////////////////////
            if (updateObj.ContainsKey("ParentID") && Convert.ToInt32(updateObj["ParentID"]) > 0)
            {
                //指定了父节点，判断当前是否修改了父节点信息，

                if (objNode != null)
                {
                    if (Convert.ToInt32(updateObj["ParentID"]) == objNode.ParentID)
                    {
                        //并未修改父节点信息，忽略
                        updateObj.Remove("PropPath");
                        updateObj.Remove("ParentID");
                        updateObj.Remove("NodeLevel");
                    }
                    else
                    {
                        if (Convert.ToInt32(updateObj["ParentID"]) == Convert.ToInt32(updateObj["ID"]))
                        {
                            throw new ArgumentException("不能以自身作为父节点");
                        }
                        //需要将新的父节点找出来，然后赋值
                        var parentNode = this.Db!.GetDbContext(string.Empty).Queryable<TreeBase<dynamic>>().AS(tableName).Where("Deleted=0 AND ID=@ID", new { ID = updateObj["ParentID"] }).First();
                        if (parentNode != null)
                        {
                            if (parentNode.ParentID == 0 || !parentNode.PropPath!.Contains(objNode.PropPath!))
                            {
                                updateObj.Remove("PropPath");
                                updateObj.Remove("NodeLevel");
                                updateObj.Add("PropPath", $"{parentNode.PropPath}{parentNode.ID}/");
                                updateObj.Add("NodeLevel", parentNode.NodeLevel + 1);
                            }
                            else {
                                //如果是本节点的子节点，抛出异常，避免形成闭环
                                throw new ArgumentException("不能以后续节点作为父节点");
                            }
                        }
                        else
                        {
                            throw new ArgumentException("指定的父节点不存在");
                        }
                    }
                }
                else
                {
                    throw new ArgumentException("找不到对应的记录");
                }

            }
            else
            {
                //不更新父节点信息
            }

            //////////////////////////////////////////////////////////
            try
            {
                if (obj.Check)
                {
                    //需要检查数据是否合法
                }
                if (obj.RepeatKeys != null && obj.RepeatKeys.Count > 0)
                {
                    //需要检查数据是否重复
                    StringBuilder stringBuilder = new StringBuilder();
                    stringBuilder.Append("ID!=@ID ");
                    var parametars = new Dictionary<string, object>();
                    parametars.Add("ID", updateObj["ID"]);
                    foreach (var keyStr in obj.RepeatKeys)
                    {
                        if (updateObj.ContainsKey(keyStr))
                        {
                            stringBuilder.Append($"And {keyStr}=@{keyStr} ");
                            parametars.Add(keyStr, updateObj[keyStr]);
                        }
                    }
                    var whereStr = stringBuilder.ToString();

                    if (Db!.GetDbContext(string.Empty).Queryable<dynamic>().AS(tableName).Where(whereStr, parametars).Count() > 0)
                    {
                        throw new Exception("存在重复数据");
                    }
                }
                var dbclient = Db!.GetDbContext(string.Empty);
                //开启事务
                dbclient.Ado.BeginTran();
                //修改当前节点的信息
                var result = dbclient.Updateable(updateObj).AS(tableName).WhereColumns("ID").IgnoreColumns("CreatorID", "ModifyTime").ExecuteCommand();
                if (result != 1)
                {
                    throw new Exception("保存数据失败!");
                }
                if (updateObj.ContainsKey("ParentID"))
                { 
                    //修改了当前节点的ParentID，则需要更新它的子节点
                    var parametarsBatch = new Dictionary<string, object>();
                    parametarsBatch.Add("oldPath", $"{objNode.PropPath}");
                    parametarsBatch.Add("newPath", updateObj["PropPath"]);
                    parametarsBatch.Add("subLevel", Convert.ToInt32(updateObj["NodeLevel"]) - Convert.ToInt32(objNode.NodeLevel));
                    parametarsBatch.Add("PropPath", $"{objNode.PropPath}{objNode.ID}/%");
                    dbclient.Ado.ExecuteCommand($"UPDATE {tableName} SET PropPath = REPLACE(PropPath,@oldPath,@newPath),NodeLevel=NodeLevel+@subLevel WHERE PropPath LIKE @PropPath", parametarsBatch);

                }
                dbclient.Ado.CommitTran();
                //dbclient.Updateable<dynamic>().AS(tableName).SetColumns(it=>it.PropPath = it.PropPath.Replace($"{objNode.PropPath}{objNode.ID}/%", updateObj["PropPath"].ToString())).Where("PropPath like @IDPath", new { IDPath = $"{objNode.PropPath}{objNode.ID}/%" }).ToList();
                return obj.Data;
                throw new Exception("保存数据失败!");
            }
            catch
            {
                throw;
            }
        }


        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="idlist">需要删除的记录ID列表</param>
        /// <returns>成功与否</returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="Exception"></exception>
        [HttpDelete("{tableName}")]
        public dynamic Delete(string tableName, [FromBody] List<int> idlist)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new ArgumentException("表名不可为空");
            }
            if (idlist == null || idlist.Count == 0)
            {
                throw new ArgumentException("参数不可为空");
            }
            var client = Db!.GetDbContext(string.Empty);
            try
            {
                client.BeginTran();
                var updateObj = new Dictionary<string, object>();
                updateObj.Add("PropPath", String.Join(",", idlist.ConvertAll<string>(new Converter<int, string>(m => m.ToString())).ToArray()));
                if (client.Ado.ExecuteCommand($"UPDATE {tableName} SET Deleted = 1 WHERE FIND_IN_SET (ID, @PropPath)", updateObj) > 0)
                {
                    client.CommitTran();
                    return true;
                }
                else
                {
                    client.RollbackTran();
                    return false;
                }
            }
            catch
            {
                throw new Exception("删除过程中发生异常");
            }
        }

        private void BuildTree(dynamic root, List<dynamic> childrenList)
        {
            List <dynamic> tempList = childrenList.Where(t=>t.ParentID == root.ID).ToList();
            foreach (var child in tempList)
            {
                BuildTree(child, childrenList);
            }
            root.Children = tempList;
        }
        private List<dynamic> BuildTree(List<dynamic> childrenList)
        {
            List<dynamic> topLevel = new List<dynamic>();
            foreach (var item in childrenList)
            {
                var parentList = childrenList.Where(t => t.ID == item.ParentID).ToList();
                var parent = parentList.Count > 0 ? parentList.First() : null;
                if (parent != null)
                {
                    if (!((IDictionary<string, object>)parent).ContainsKey("Children"))
                    {
                        parent.Children = new List<dynamic>();
                    }
                    parent.Children.Add(item);
                }
                else
                {
                    topLevel.Add(item);
                }
            }
            return topLevel;
        }
    }
}
